package com.ukao.cashregister.rfid;

import android.util.Log;

import com.ukao.cashregister.eventbus.MembershipCardEvent;
import com.ukao.cashregister.utils.L;

import org.greenrobot.eventbus.EventBus;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;

import static com.ukao.cashregister.eventbus.MembershipCardEvent.Message.fali;

/**
 * Created by herego on 2017/5/23.
 */



public class RfidHelper {
    public enum RfidCmdType{
        RFID_CMD_TYPE_OPEN_CONTROLLER, //开启天线和寻卡控制
        RFID_CMD_TYPE_AUTO_SCAN, //开启自动扫描ID
        RFID_CMD_TYPE_SCAN_CARD, //寻卡
        RFID_CMD_TYPE_READ_BLOCK_INFO, //读卡块信息
        RFID_CMD_TYPE_WRITE_BLOCK_INFO, //写卡快信息
        RFID_CMD_TYPE_INIT_WALLET, //初始化钱包
        RFID_CMD_TYPE_READ_WALLET, //读取钱包
        RFID_CMD_TYPE_RECHARGE_WALLET, //充值钱包
        RFID_CMD_TYPE_PAYMENT_WALLET, //扣款
        RFID_CMD_TYPE_BACKUP_WALLET,  //备份钱包
        RFID_CMD_TYPE_MODIFY_KEY     //修改密钥
    }

    public class RfidResultInfo{
        public RfidCmdType mRfidCmdType;
        public String mResultData;
    }

    private static RfidHelper mRfidHelper = null;
    private SerialPortHelper mSerialPortHelper = new SerialPortHelper();
    private Map<RfidCmdType,byte[]> mCmdMap = new HashMap<RfidCmdType,byte[]>();
    private InputStream mInputStream = null;
    private OutputStream mOutputStream = null;
    public boolean mIsStop = true;
    public Thread mRecvThread;
//    private byte[] mKeyArray = new byte[]{(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF};
    private byte[] mKeyArray = new byte[]{(byte)0x31,(byte)0x45,(byte)0x54,(byte)0x33,(byte)0x49,(byte)0x4F};
    private byte[] mTempKeyArray = new byte[]{(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF};
    boolean mIsModifyKey = false;
    private LinkedList<RfidCmdType> mCmdList = new LinkedList();

    private void initCmd(){
        //寻卡 固定 起始0x02+ID0x00+长度0x03+命令0x25+数据+校验码0x00+结束0x03
        byte[] bytes3 = new byte[]{0x02,0x00,0x03,0x25,0x26,0x00,0x00};
        mCmdMap.put(RfidCmdType.RFID_CMD_TYPE_SCAN_CARD,bytes3);

        //读块  起始0x02+ID0x00+长度0x0A+命令0x20+控制模式0x01+读块的数量0x01+起始块地址0x03+6字节密钥具体数据+1字节校验（异或 0x0D）+结束0x03
        byte[] bytes4 = new byte[]{0x02,0x00,0x0A,0x20,0x01,0x01};
        mCmdMap.put(RfidCmdType.RFID_CMD_TYPE_READ_BLOCK_INFO,bytes4);

        //写块  起始0x02+ID0x00+长度0x1A+命令0x21+控制模式0x01+读块的数量0x01+起始块地址0x03+6字节密钥具体数据+16字节数据+1字节校验（异或 0x0D）+结束0x03
        byte[] bytes5 = new byte[]{0x02,0x00,0x1A,0x21,0x01,0x01};
        mCmdMap.put(RfidCmdType.RFID_CMD_TYPE_WRITE_BLOCK_INFO,bytes5);
    }

    private RfidHelper(){
        initCmd();
    }

    public void closeSerialPort(){
        mIsStop = true;
        if (mRecvThread != null) {
            mRecvThread.interrupt();
        }
        mRecvThread=null;
         mSerialPortHelper.closePort();
        mRfidHelper=null;
    }

    public boolean openSerialPort(){
        if(mIsStop == false){
            Log.i("Debug:","serial open already");
            return true;
        }
//        if(mSerialPortHelper.initPort("/dev/ttymxc1",115200)) {
        if(mSerialPortHelper.initPort("/dev/ttyS4",9600)) {
            mInputStream = mSerialPortHelper.getInputStream();
            mOutputStream = mSerialPortHelper.getOutputStream();
            mIsStop = false;
            mRecvThread = new RecvThread();
            mRecvThread.start();
            return true;
        }
        Log.i("Error:","serial open failure");
        return false;
    }




    //接收返回结果
    private class RecvThread extends Thread {
        @Override
        public void run() {
            Log.i("Debug:","detect serial port start");
            L.i("!mIsStop && !isInterrupted()="+!mIsStop + !isInterrupted());
            while (!mIsStop && !isInterrupted()) {

                int size;
                byte[] buffer = new byte[64];
                if (mInputStream == null) {
                    return;
                }
                try {
                    Thread.currentThread().sleep(1000);
//                    Thread.sleep(1000);
                    size = mInputStream.read(buffer);
                    if (size>0) {
                        Log.i("Debug:","-------------------");
                        printHexArray(buffer,size);
                        parseResult(buffer,size);
                    }else{

                    }

                } catch (IOException e) {
                    e.printStackTrace();
                }catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            Log.i("Debug:","detect serial port stop");
        }
    }

    public void parseResult(byte[] resultArray,int size){
        RfidResultInfo rfidResultInfo = new RfidResultInfo();
        rfidResultInfo.mResultData = "1";
        if(!mCmdList.isEmpty())
        {
            switch (mCmdList.removeFirst())
            {
                case RFID_CMD_TYPE_SCAN_CARD:
                    rfidResultInfo.mRfidCmdType = RfidCmdType.RFID_CMD_TYPE_SCAN_CARD;
                    if(resultArray[3] == 0x00) {
                        String cardId = "";
                        for (int i = 5; i < 5+4; ++i) {
                            cardId += String.format("%02x", (int) (0x0FF & resultArray[i]));
                        }
                        Log.i("Debug:", "寻卡成功  用户ID:"+cardId);
                        rfidResultInfo.mResultData = cardId;
                        MembershipCardEvent.postHasData(MembershipCardEvent.Message.update, rfidResultInfo);
                    }else{

                        Log.i("Debug:", "寻卡失败");
                    }
                    break;
                case RFID_CMD_TYPE_READ_BLOCK_INFO:
                    rfidResultInfo.mRfidCmdType = RfidCmdType.RFID_CMD_TYPE_READ_BLOCK_INFO;
                    if(resultArray[3] == 0x00) {
                        byte[] dataArray = new byte[16];
                        System.arraycopy(resultArray, 8, dataArray, 0, 16);
                        String userId = new String(dataArray);
                        Log.i("Debug:", "读块成功 用户ID:"+userId);
                        rfidResultInfo.mResultData = userId;
                      //  MembershipCardEvent.postHasData(MembershipCardEvent.Message.update, rfidResultInfo);
                    }else{
                        rfidResultInfo.mResultData = "0";
                     //   MembershipCardEvent.postHasData(MembershipCardEvent.Message.update, rfidResultInfo);
                        Log.i("Debug:", "读块失败");
                    }
                    switch (  rfidResultInfo.mResultData) {
                        case "1":/*读卡失败*/
                            MembershipCardEvent.postHasData(fali,"读卡失败");
                            break;
                        case "0":/*没有放卡*/
                            MembershipCardEvent.postNoData(MembershipCardEvent.Message.notFound);
                            break;
                        default:/*读卡信息*/
                            MembershipCardEvent.postHasData(MembershipCardEvent.Message.add, rfidResultInfo.mResultData);
                            break;
                    }

                    break;
                case RFID_CMD_TYPE_WRITE_BLOCK_INFO:
                    rfidResultInfo.mRfidCmdType = RfidCmdType.RFID_CMD_TYPE_WRITE_BLOCK_INFO;
                    if(resultArray[3] == 0x00) {
                        if (!mIsModifyKey) {
                            Log.i("Debug:", "写块成功");
                            EventBus.getDefault().post("写块成功");
                        } else {
                            Log.i("Debug:", "密钥修改成功");
                            System.arraycopy(mTempKeyArray, 0, mKeyArray, 0, mKeyArray.length);
                            printHexArray(mKeyArray, mKeyArray.length);
                        }
                    }else{
                        if (!mIsModifyKey) {
                            Log.i("Debug:", "写块失败");
                        }else{
                            Log.i("Debug:", "密钥修改失败");
                        }
                    }
                    break;
                default:
                    Log.i("Debug:", "不认识指令");
                    break;
            }
        }
    }

    public void printHexArray(byte[] array,int size){
        String text = "";
        for(int i=0;i < size;++i){
            text += String.format("0x%02x ",(int)(0x0FF&array[i]));
        }
        String lineSeparator = System.getProperty("line.separator", "\n");
        text += lineSeparator;
        Log.i("Serial:",text);
    }

    public int setRfidData(byte[] sendData,int sendDataLength,byte[] data,int dataLength,int limitLength){
        int len = sendDataLength;

        //密钥
        System.arraycopy(mKeyArray,0,sendData,len,mKeyArray.length);
        len += mKeyArray.length;

        //数据
        for(int i=0;i < limitLength;++i){
            if(data != null && i < dataLength){
                sendData[len+i] = data[i];
            }else{
                sendData[len+i] = 0x00;
            }
        }
        len += limitLength;

        //校验码
        sendData[len] = this.getCheckCode(sendData,len);
        len += 1;

        return len;
    }

    //发送指令
    public void sendCmd(RfidCmdType rfidCmdType,int blockIndex,byte[] data,int dataLength){

        //发送数据缓存
        byte[] sendData = new byte[64];
        int len = 0;

        //初始化命令类型
        byte[] tmpData = this.mCmdMap.get(rfidCmdType);
        System.arraycopy(tmpData,0,sendData,0,tmpData.length);
        len += tmpData.length;

        //处理块号
        if(blockIndex != -1) {
            sendData[len] = (byte) (0xFF & blockIndex);
            len += 1;
        }

        //针对命令类型添加附加数据
        switch (rfidCmdType){
            case RFID_CMD_TYPE_READ_BLOCK_INFO: //读卡块信息
            case RFID_CMD_TYPE_READ_WALLET: //读取钱包
                len = setRfidData(sendData,len,data,dataLength,0);
                break;
            case RFID_CMD_TYPE_WRITE_BLOCK_INFO: //写卡快信息
                len = setRfidData(sendData,len,data,dataLength,16);
                break;
            case RFID_CMD_TYPE_INIT_WALLET: //初始化钱包
                len = setRfidData(sendData,len,data,dataLength,4);
                break;
            case RFID_CMD_TYPE_RECHARGE_WALLET: //充值钱包
                len = setRfidData(sendData,len,data,dataLength,4);
                break;
            case RFID_CMD_TYPE_PAYMENT_WALLET: //扣款
                len = setRfidData(sendData,len,data,dataLength,4);
                break;
            case RFID_CMD_TYPE_BACKUP_WALLET:  //备份钱包
                len = setRfidData(sendData,len,data,dataLength,0);
                break;
            case RFID_CMD_TYPE_MODIFY_KEY: //修改密钥
                len = setRfidData(sendData,len,data,dataLength,16);
                printHexArray(data,dataLength);
                break;
            default:
                break;
        }

        //添加结束字符
        byte[] endData = new byte[]{0x03};
        System.arraycopy(endData,0,sendData,len,endData.length);
        len += endData.length;

        try{
            if(mOutputStream == null){
                Log.i("Error:","mOutputStream is null");
                return;
            }
            printHexArray(sendData,len);
            mCmdList.add(rfidCmdType);
            mOutputStream.write(sendData,0,len);
        }catch (Exception ex){
            Log.i("Error:","send serial port data failure");
        }
    }

    public void openRfidController(){
        sendCmd(RfidCmdType.RFID_CMD_TYPE_OPEN_CONTROLLER,-1,null,0);
    }

    public void scanCard(){
        sendCmd(RfidCmdType.RFID_CMD_TYPE_SCAN_CARD,-1,null,0);
    }

    public void openAutoScanCard(){
        sendCmd(RfidCmdType.RFID_CMD_TYPE_AUTO_SCAN,-1,null,0);
    }

    public void readRfid(int blockIndex){

        //命令操作
        sendCmd(RfidCmdType.RFID_CMD_TYPE_READ_BLOCK_INFO,blockIndex,null,0);

    }

    public void writeRfid(String data,int blockIndex){
        mIsModifyKey = false;
        sendCmd(RfidCmdType.RFID_CMD_TYPE_WRITE_BLOCK_INFO,blockIndex,data.getBytes(),data.getBytes().length);
    }

    public void initRfidWallet(int blockIndex){
        sendCmd(RfidCmdType.RFID_CMD_TYPE_INIT_WALLET,blockIndex,null,0);
    }

    public void readRfidWallet(int blockIndex){
        sendCmd(RfidCmdType.RFID_CMD_TYPE_READ_WALLET,blockIndex,null,0);
    }

    public void rechargeRfidWallet(int blockIndex,int money){
        byte[] array = new byte[4];
        for(int i=0;i < array.length;++i) {
            array[i] = (byte)(0xFF & money);
            money = money>>8;
        }
        sendCmd(RfidCmdType.RFID_CMD_TYPE_RECHARGE_WALLET,blockIndex,array,array.length);
    }

    public void paymentRfidWallet(int blockIndex,int money){
        byte[] array = new byte[4];
        for(int i=0;i < array.length;++i) {
            array[i] = (byte)(0xFF & money);
            money = money>>8;
        }
        sendCmd(RfidCmdType.RFID_CMD_TYPE_PAYMENT_WALLET,blockIndex,array,array.length);
    }

    public void modifyRfidKey(int blockIndex,String key){
        byte[] array = key.getBytes();
        int len = key.getBytes().length;
        if(len > 0) {
            mIsModifyKey = true;
            byte[] dataArray = new byte[16];

            //新密钥
            System.arraycopy(array, 0, dataArray, 0, len>6?6:len);
            Arrays.fill(mTempKeyArray,(byte) 0);
            System.arraycopy(array, 0, mTempKeyArray, 0, len>6?6:len);

            //控制字 B密钥
            System.arraycopy(new byte[]{(byte)0xFF,0x07,0x08,0x69,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF}, 0, dataArray, 6, 10);

            //发送指令
            sendCmd(RfidCmdType.RFID_CMD_TYPE_MODIFY_KEY, blockIndex, dataArray, dataArray.length);
        }
    }

    public byte getCheckCode(byte[] array,int len){
        byte ret = array[1];
        for(int i=1;i < len;++i){
            ret ^= array[i];
        }
        return ret;
    }

    public static RfidHelper getInstance(){
        if(mRfidHelper == null) {
            mRfidHelper = new RfidHelper();
        }
        return  mRfidHelper;
    }

}
